Wang Haihua
🍈 🍉🍊 🍋 🍌
多元回归中的普通最小二乘法是拟合参数向量 $\beta$, 使得 $\|X \beta-Y\|_{2}^{2}$ 达到最 小值。岭回归是选择合适的参数 $k \geq 0$, 拟合参数向量 $\boldsymbol{\beta}$, 使得 $\|X \boldsymbol{\beta}-\boldsymbol{Y}\|_{2}^{2}+\boldsymbol{k}\|\boldsymbol{\beta}\|_{2}^{2}$ 达到最小值, 解决了 $X^{T} X$ 不可逆的问题。LASSO 回归, 是 选择合适的参数 $k \geq 0$, 拟合参数向量 $\beta$, 使得 $$ J(\beta)=\|X \beta-Y\|_{2}^{2}+k\|\beta\|_{1} $$ 达到最小值,其中 $\boldsymbol{k}\|\boldsymbol{\beta}\|_{1}$ 为目标函数的惩罚项, $\boldsymbol{k}$ 为惩罚系数。
由于式(12.17)中的惩罚项是关于回归系数 的绝对值之和,因此惩罚项在零点处是不可导的,那么应用在岭回归上的最小二乘法在此失效,不仅如此,梯度下降法、牛顿法与拟牛顿法都无法计算出LASSO回归的拟合系数。坐标下降法可以求得LASSO回归系数,坐标下降法与梯度下降法类似,都属于迭代算法,所不同的是坐标轴下降法是沿着坐标轴下降,而梯度下降则是沿着梯度的负方向下降,具体的数学原理这里就不介绍了。
由于拟合LASSO回归模型参数时,使用的损失函数(机器学习中的用语)式(12.17)中包含惩罚系数 ,因此在计算模型回归系数之前,仍然需要得到最理想的$k$值。与岭回归模型类似,$k$值的确定可以通过定性的可视化方法。
$$\begin{array}{ccccc|ccccc} \hline \text { 年份 } & x_{1} & x_{2} & x_{3} & y & \text { 年份 } & x_{1} & x_{2} & x_{3} & y \\ \hline 1949 & 149.3 & 4.2 & 108.1 & 15.9 & 1955 & 202.1 & 2.1 & 146.0 & 22.7 \\ 1950 & 171.5 & 4.1 & 114.8 & 16.4 & 1956 & 212.4 & 5.6 & 154.1 & 26.5 \\ 1951 & 175.5 & 3.1 & 123.2 & 19.0 & 1957 & 226.1 & 5.0 & 162.3 & 28.1 \\ 1952 & 180.8 & 3.1 & 126.9 & 19.1 & 1958 & 231.9 & 5.1 & 164.3 & 27.6 \\ 1953 & 190.7 & 1.1 & 132.1 & 18.8 & 1959 & 239.0 & 0.7 & 167.6 & 26.3 \\ 1954 & 202.1 & 2.2 & 137.7 & 20.4 & & & & & \\ \hline \end{array}$$下表 是 Malinvand 于 1966 年提出的研究法国经济问题的 一组数据。所考虑的因变量为进口总额 $y$, 三个解释变量分别为: 国内总产 值 $x_{1}$, 储存量 $x_{2}$, 总消费量 $x_{3}$ (单位均为 10 亿法郎)。
求例 $12.3$ 的 LASSO 回归方程。
解 画出的 $k$ 与LASSO回归系数的关系图如图12.2所示, 从图中可以 看出选 $\boldsymbol{k}=\mathbf{0 . 2 1}$ 较好。对应的标准化LASSO回归方程为 $$ \hat{y}^{*}=0.0136 x_{2}^{*}+0.7614 x_{3}^{*}, $$ 将标准化回归方程还原后得 $$ \hat{y}=-1.6602+0.0374 x_{2}+0.1677 x_{3} \text {, } $$ 模型的拟合优度 $R^{2}=0.9061$ 。从计算结果可以看出, LASSO 回归可以非常 方便地实现自变量的笑选。
代码
import numpy as np; import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso, LassoCV
from scipy.stats import zscore
plt.rc('font',size=16)
plt.rc('text', usetex=True) #没装LaTeX宏包把该句注释
a=np.loadtxt("data/economic.txt")
n=a.shape[1]-1 #自变量的总个数
aa=zscore(a) #数据标准化
x=aa[:,:n]; y=aa[:,n] #提出自变量和因变量观测值矩阵
b=[] #用于存储回归系数的空列表
kk=np.logspace(-4,0,100) #循环迭代的不同k值
for k in kk:
md=Lasso(alpha=k).fit(x,y)
b.append(md.coef_)
st=['s-r','*-k','p-b'] #下面画图的控制字符串
for i in range(3): plt.plot(kk,np.array(b)[:,i],st[i]);
plt.legend(['$x_1$','$x_2$','$x_3$'],fontsize=15); plt.show()
mdcv=LassoCV(alphas=np.logspace(-4,0,100)).fit(x,y);
print("最优alpha=",mdcv.alpha_)
#md0=Lasso(mdcv.alpha_).fit(x,y) #构建并拟合模型
md0=Lasso(0.21).fit(x,y) #构建并拟合模型
cs0=md0.coef_ #提出标准化数据的回归系数b1,b2,b3
print("标准化数据的所有回归系数为:",cs0)
mu=np.mean(a,axis=0);
s=np.std(a,axis=0,ddof=1) #计算所有指标的均值和标准差
params=[mu[-1]-s[-1]*sum(cs0*mu[:-1]/s[:-1]),s[-1]*cs0/s[:-1]]
print("原数据的回归系数为:",params)
print("拟合优度:",md0.score(x,y))
\begin{array}{cccccc} \hline \text { 年 } & x_{1} & x_{2} & x_{3} & x_{4} & y \\ \hline 1994 & 3496.2 & 3.43 & 136.69 & 111.78 & 205.42 \\ 1995 & 4283 & 3.52 & 145.27 & 115.7 & 249.96 \\ 1996 & 4838.9 & 3.73 & 147.52 & 118.58 & 289.67 \\ 1997 & 5160.3 & 3.94 & 158.25 & 122.64 & 358.36 \\ 1998 & 5425.1 & 4.16 & 163 & 127.85 & 423.65 \\ 1999 & 5854 & 4.37 & 183.2 & 135.17 & 533.88 \\ 2000 & 6280 & 4.59 & 207 & 140.27 & 625.33 \\ 2001 & 6859.6 & 4.81 & 234.17 & 169.8 & 770.78 \\ 2002 & 7702.8 & 5.02 & 325.1 & 176.52 & 968.98 \\ \hline \end{array}在建立中国私人轿车拥有量模型时, 主要考虑以下因素: (1) 城镇居民家庭人均可支配收入 $x_{1}$ (元),(2) 全国城镇人口 $x_{2}$ (亿人), (3) 全国汽车产量 $x_{3}$ (万辆), (4) 全国公路长度 $x_{4}$ (万公里) 。具体数据见表 $12.3$, 其中 $y$ 表示中国私人轿车拥有量 (万䢀)。试建立 $y$ 的经验公式。
对于上述问题, 我们可以直接用普通的最小二乘法建立 $y$ 关于四个解释 变量 $x_{1}, x_{2}, x_{3}$ 和 $x_{4}$ 的回归方程为 $$ \hat{y}=-1028.4134-0.0159 x_{1}+245.6120 x_{2}+1.6316 x_{3}+2.0294 x_{4} \text {, } $$ 模型的检验见下面程序运行结果, 我们这里就不具体给出了。 在 $\alpha=0.05$ 的水平下, 以上的回归方程是显著的。但变量 $x_{1}$ 对 $y$ 是不显 著的, 且回归方程中 $x_{1}$ 前面的系数为负值也不合理。
我们选择 $k=0.05$, 建立的 LASSO 回归方程为 $$ \hat{y}=-908.2059+203.0938 x_{2}+1.4562 x_{3}+2.0469 x_{4} \text {. } $$
import numpy as np; import matplotlib.pyplot as plt
import statsmodels.api as sm
from sklearn.linear_model import Lasso
from scipy.stats import zscore
#plt.rc('text', usetex=True) #没装LaTeX宏包把该句注释
a=np.loadtxt("data/car.txt") #加载表中的9行5列数据
n=a.shape[1]-1 #自变量的总个数
x=a[:,:n] #提出自变量观测值矩阵
X = sm.add_constant(x)
md=sm.OLS(a[:,n],X).fit() #构建并拟合模型
print(md.summary()) #输出模型的所有结果
aa=zscore(a) #数据标准化
x=aa[:,:n]; y=aa[:,n] #提出自变量和因变量观测值矩阵
b=[] #用于存储回归系数的空列表
kk=np.logspace(-4,0,100) #循环迭代的不同k值
for k in kk:
md=Lasso(alpha=k).fit(x,y)
b.append(md.coef_)
st=['s-r','*-k','p-b','^-y'] #下面画图的控制字符串
for i in range(n): plt.plot(kk,np.array(b)[:,i],st[i]);
plt.legend(['$x_1$','$x_2$','$x_3$','$x_4$'],fontsize=15); plt.show()
md0=Lasso(0.05).fit(x,y) #构建并拟合模型
cs0=md0.coef_ #提出标准化数据的回归系数b1,b2,b3,b4
print("标准化数据的所有回归系数为:",cs0)
mu=a.mean(axis=0); s=a.std(axis=0,ddof=1) #计算所有指标的均值和标准差
params=[mu[-1]-s[-1]*sum(cs0*mu[:-1]/s[:-1]),s[-1]*cs0/s[:-1]]
print("原数据的回归系数为:",params)
print("拟合优度:",md0.score(x,y))
import numpy as np; import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso, LassoCV
from scipy.stats import zscore
plt.rc('font',size=16)
plt.rc('text', usetex=True) #没装LaTeX宏包把该句注释
a=np.loadtxt("data/economic.txt")
n=a.shape[1]-1 #自变量的总个数
aa=zscore(a) #数据标准化
x=aa[:,:n]; y=aa[:,n] #提出自变量和因变量观测值矩阵
b=[] #用于存储回归系数的空列表
kk=np.logspace(-4,0,100) #循环迭代的不同k值
for k in kk:
md=Lasso(alpha=k).fit(x,y)
b.append(md.coef_)
st=['s-r','*-k','p-b'] #下面画图的控制字符串
for i in range(3): plt.plot(kk,np.array(b)[:,i],st[i]);
plt.legend(['$x_1$','$x_2$','$x_3$'],fontsize=15);
plt.savefig('images/exp0901.png')
plt.show()
mdcv=LassoCV(alphas=np.logspace(-4,0,100)).fit(x,y);
print("最优alpha=",mdcv.alpha_)
#md0=Lasso(mdcv.alpha_).fit(x,y) #构建并拟合模型
md0=Lasso(0.21).fit(x,y) #构建并拟合模型
cs0=md0.coef_ #提出标准化数据的回归系数b1,b2,b3
print("标准化数据的所有回归系数为:",cs0)
mu=np.mean(a,axis=0);
s=np.std(a,axis=0,ddof=1) #计算所有指标的均值和标准差
params=[mu[-1]-s[-1]*sum(cs0*mu[:-1]/s[:-1]),s[-1]*cs0/s[:-1]]
print("原数据的回归系数为:",params)
print("拟合优度:",md0.score(x,y))
最优alpha= 0.0001 标准化数据的所有回归系数为: [0. 0.01358604 0.76138391] 原数据的回归系数为: [-1.6602049109195391, array([0. , 0.03742957, 0.16765569])] 拟合优度: 0.9061154424386824
import numpy as np; import matplotlib.pyplot as plt
import statsmodels.api as sm
from sklearn.linear_model import Lasso
from scipy.stats import zscore
#plt.rc('text', usetex=True) #没装LaTeX宏包把该句注释
a=np.loadtxt("data/car.txt") #加载表中的9行5列数据
n=a.shape[1]-1 #自变量的总个数
x=a[:,:n] #提出自变量观测值矩阵
X = sm.add_constant(x)
md=sm.OLS(a[:,n],X).fit() #构建并拟合模型
print(md.summary()) #输出模型的所有结果
aa=zscore(a) #数据标准化
x=aa[:,:n]; y=aa[:,n] #提出自变量和因变量观测值矩阵
b=[] #用于存储回归系数的空列表
kk=np.logspace(-4,0,100) #循环迭代的不同k值
for k in kk:
md=Lasso(alpha=k).fit(x,y)
b.append(md.coef_)
st=['s-r','*-k','p-b','^-y'] #下面画图的控制字符串
for i in range(n): plt.plot(kk,np.array(b)[:,i],st[i]);
plt.legend(['$x_1$','$x_2$','$x_3$','$x_4$'],fontsize=15); plt.show()
md0=Lasso(0.05).fit(x,y) #构建并拟合模型
cs0=md0.coef_ #提出标准化数据的回归系数b1,b2,b3,b4
print("标准化数据的所有回归系数为:",cs0)
mu=a.mean(axis=0); s=a.std(axis=0,ddof=1) #计算所有指标的均值和标准差
params=[mu[-1]-s[-1]*sum(cs0*mu[:-1]/s[:-1]),s[-1]*cs0/s[:-1]]
print("原数据的回归系数为:",params)
print("拟合优度:",md0.score(x,y))
D:\software_install\anaconda\lib\site-packages\scipy\stats\stats.py:1541: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=9 warnings.warn("kurtosistest only valid for n>=20 ... continuing "
OLS Regression Results ============================================================================== Dep. Variable: y R-squared: 0.999 Model: OLS Adj. R-squared: 0.999 Method: Least Squares F-statistic: 1623. Date: Sun, 22 May 2022 Prob (F-statistic): 1.14e-06 Time: 15:02:51 Log-Likelihood: -28.919 No. Observations: 9 AIC: 67.84 Df Residuals: 4 BIC: 68.82 Df Model: 4 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ const -1028.4134 58.305 -17.638 0.000 -1190.294 -866.532 x1 -0.0159 0.015 -1.043 0.356 -0.058 0.026 x2 245.6120 34.213 7.179 0.002 150.622 340.602 x3 1.6316 0.178 9.148 0.001 1.136 2.127 x4 2.0294 0.580 3.500 0.025 0.420 3.639 ============================================================================== Omnibus: 0.575 Durbin-Watson: 2.151 Prob(Omnibus): 0.750 Jarque-Bera (JB): 0.560 Skew: 0.368 Prob(JB): 0.756 Kurtosis: 2.025 Cond. No. 1.24e+05 ============================================================================== Notes: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified. [2] The condition number is large, 1.24e+05. This might indicate that there are strong multicollinearity or other numerical problems.
标准化数据的所有回归系数为: [0. 0.44723893 0.34045523 0.18555833] 原数据的回归系数为: [-908.2058953990941, array([ 0. , 203.09384921, 1.45621116, 2.04693134])] 拟合优度: 0.9965807211503689
def load_car():
""" Economic data
Yields:
-------
economic : a pandas DataFrame object that contains 9 samples with the columns of
'城镇居民家庭人均可支配收入/元','全国城镇人口/亿人',' 全国汽车产量/万量','全国公路长度/万公里','中国私人轿车拥有量/万辆'
Use :
For explaination model practice
Reference:
"""
data = np.array([[3.4962e+03, 3.4300e+00, 1.3669e+02, 1.1178e+02, 2.0542e+02],
[4.2830e+03, 3.5200e+00, 1.4527e+02, 1.1570e+02, 2.4996e+02],
[4.8389e+03, 3.7300e+00, 1.4752e+02, 1.1858e+02, 2.8967e+02],
[5.1603e+03, 3.9400e+00, 1.5825e+02, 1.2264e+02, 3.5836e+02],
[5.4251e+03, 4.1600e+00, 1.6300e+02, 1.2785e+02, 4.2365e+02],
[5.8540e+03, 4.3700e+00, 1.8320e+02, 1.3517e+02, 5.3388e+02],
[6.2800e+03, 4.5900e+00, 2.0700e+02, 1.4027e+02, 6.2533e+02],
[6.8596e+03, 4.8100e+00, 2.3417e+02, 1.6980e+02, 7.7078e+02],
[7.7028e+03, 5.0200e+00, 3.2510e+02, 1.7652e+02, 9.6898e+02]])
car = pd.DataFrame(data,index=range(1994,2003),columns=['城镇居民家庭人均可支配收入/元','全国城镇人口/亿人',' 全国汽车产量/万量','全国公路长度/万公里','中国私人轿车拥有量/万辆'])
return car